package vm

import (
	"context"
	"encoding/json"
	"itam/internal/dao"
	"itam/internal/model"
	"itam/internal/service"
	"net"
	"time"

	httplib "github.com/beego/beego/v2/client/httplib"
	"github.com/gogf/gf/v2/frame/g"
)

type sVm struct{}

func init() {
	service.RegisterVm(New())
}

func New() *sVm {
	return &sVm{}
}

// Create 新增
func (s *sVm) Create(ctx context.Context, in model.VmCreateInput) (out model.VmCreateOutput, err error) {
	vmId, err := dao.Vm.Ctx(ctx).Data(in).InsertAndGetId()
	if err != nil {
		return out, err
	}
	return model.VmCreateOutput{Id: int(vmId)}, nil
}

// Delete 删除
func (s *sVm) Delete(ctx context.Context, id int) (err error) {
	_, err = dao.Vm.Ctx(ctx).Where(dao.Vm.Columns().Id, id).Delete()
	return
}

// Update 修改
func (s *sVm) Update(ctx context.Context, in model.VmUpdateInput) error {
	_, err := dao.Vm.Ctx(ctx).Data(in).FieldsEx(dao.Vm.Columns().Id).Where(dao.Vm.Columns().Id, in.Id).Update()
	return err
}

// GetList 列表查询
func (s *sVm) GetList(ctx context.Context, in model.VmGetListInput) (out *model.VmGetListOutput, err error) {
	var m = dao.Vm.Ctx(ctx)
	out = &model.VmGetListOutput{
		List: make([]model.VmListItem, 0),
		Page: in.Page,
		Size: in.Size,
	}
	if in.EnvId > 0 {
		m = m.Where(dao.Vm.Columns().EnvId, in.EnvId)
	}
	if in.PmId > 0 {
		m = m.Where(dao.Vm.Columns().PmId, in.PmId)
	}
	if in.IpAddress != "" {
		m = m.Where(dao.Vm.Columns().IpAddress, in.IpAddress)
	}
	if in.Name != "" {
		m = m.WhereLike(dao.Vm.Columns().Name, "%"+in.Name+"%")
	}
	if in.RecomandStatus != "" {
		m = m.Where(dao.Vm.Columns().RecomandStatus, in.RecomandStatus)
	}
	if in.OsType != "" {
		m = m.Where(dao.Vm.Columns().OsType, in.OsType)
	}
	if in.Owner != "" {
		m = m.Where(dao.Vm.Columns().Owner, in.Owner)
	}
	m = m.Page(in.Page, in.Size)
	m = m.OrderDesc(dao.Vm.Columns().Id)

	// 执行查询
	out.Total, err = m.Count()
	if err != nil {
		return out, err
	}
	if out.Total == 0 {
		return out, nil
	}
	// 虚拟机
	if err := m.Scan(&out.List); err != nil {
		return out, err
	}
	// 物理机
	pRs, err := dao.Pm.Ctx(ctx).All()
	if err != nil {
		return out, err
	}
	pMap := pRs.MapKeyInt(dao.Pm.Columns().Id)

	// 环境
	eRs, err := dao.Env.Ctx(ctx).All()
	if err != nil {
		return out, err
	}
	eMap := eRs.MapKeyInt(dao.Env.Columns().Id)

	// 循环处理
	for i := 0; i < len(out.List); i++ {
		if eMap[out.List[i].EnvId]["name"] == nil {
			out.List[i].EnvName = ""
		} else {
			out.List[i].EnvName = eMap[out.List[i].EnvId]["name"].(string)
		}
		if pMap[out.List[i].PmId]["name"] == nil {
			out.List[i].PmName = ""
		} else {
			out.List[i].PmName = pMap[out.List[i].PmId]["name"].(string)
		}

	}
	return

}

func CheckStatus(ctx context.Context) {
	var m = dao.Vm.Ctx(ctx)
	if vms, err := m.All(); err != nil {
		g.Log().Error(ctx, err)
	} else {
		vmMap := vms.MapKeyInt(dao.Vm.Columns().Id)
		for _, entry := range vmMap {
			var checkResErr error
			status := entry["recomand_status"].(string)
			ip := entry["ip_address"].(string)
			os := entry["os_type"].(string)

			if os == "windows" {
				checkResErr = TcpConnect(ip + ":3389")
			} else if os == "linux" {
				checkResErr = TcpConnect(ip + ":22")
			}
			g.Log().Info(ctx, status+ip+os)
			g.Log().Info(ctx, checkResErr)
			// 如果status为on但测结果却不通则告警
			// 如果status为off但测结果通则告警
			if status == "on" && checkResErr != nil {
				go SendFxxk(ctx, ip)
			} else if status == "off" && checkResErr == nil {
				go SendFxxk(ctx, ip)
			}
		}
	}

}

func TcpConnect(address string) error {
	nets := new(net.Dialer)
	nets.Timeout = time.Millisecond * 3000
	conn, err := nets.Dial("tcp", address)
	if err != nil {
		return err
	}
	defer conn.Close()
	return nil
}

func SendFxxk(ctx context.Context, ipAddress string) {
	// 发送告警信息
	reqBody := fxxkRequestBody{}
	contentFooter := "详情请登陆itam查询详情"
	reqBody.Title = "主机状态不正确"
	reqBody.Content = "主机" + ipAddress + "状态与预期状态不一致！" + contentFooter
	reqBody.UserAccounts = "weishun_chen"
	req := httplib.Post("https://api.mhealth100.com/gateway/alarm/message/fxiaoke/text")
	req.Header("Content-Type", "application/json;charset=UTF-8")
	if b, err := json.Marshal(reqBody); err != nil {
		g.Log().Error(ctx, err)
	} else {
		req.Body(b)
		if resp, err := req.Response(); err != nil {
			g.Log().Error(ctx, err)
		} else {
			resp.Body.Close()
		}
	}

}

type fxxkRequestBody struct {
	Content      string `json:"content"`
	Title        string `json:"title"`
	UserAccounts string `json:"userAccounts"`
}
